/**
 *  @file  vsFunctions.h version 1.0 2007-11-20 
 *  @brief All the independent functions are defined in this file.
 *  Copyright (c) 2007 by @author <abitfree@gmail.com>
 */

#ifndef __VS_FUNCTIONS_H__
#define __VS_FUNCTIONS_H__

#include "vsDefines.h"

namespace vs
{

/// Delete a pointer safely.
template<typename T>
INLINE
void SafeDelete(T* &p)
{
	delete p;
	p = 0;
}

/// Delete a pointer array safely.
template<typename T>
INLINE
void SafeDeleteArray(T* &p)
{
	delete[] p;
	p = 0;
}


///////////////////////////////////////////////////////////////////////////////
// For Endian. 

/// Check the Endian of the machine.
INLINE
int CheckEndian()
{
	union
	{
		short int s;
		char bytes[sizeof(short int)];
	} data;
	data.s = 0x0102;

	if (data.bytes[0] == 0x01)
	{
		return BIG_ENDIAN;
	}
	else if (data.bytes[0] == 0x02)
	{
		return LITTLE_ENDIAN;
	}
	else
	{
		return UNKNOWN_ENDIAN;
	}
}


///////////////////////////////////////////////////////////////////////////////
// For other global functions.

/// Get file name from path.
INLINE
const char* GetFileName(const char *pszFullPath)
{
#ifdef WIN32
	char cSplitChar = '\\';
#else
	char cSplitChar = '/';
#endif

	const char *pszFileName = strrchr(pszFullPath, cSplitChar);
	if (pszFileName == 0)
	{
		return pszFullPath;
	}
	else
	{
		return pszFileName + 1;
	}
}


/**
 * @brief Set the current process to be a background daemon.
 *
 * @param pszWorkDir the working directory, if it's null, use the default current directory.
 */
INLINE
void MakeDaemon(const char *pszWorkDir)
{
#ifdef WIN32
	// todo: i don't know what to do for windows.
#else
	int pid;
	int fd0, fd1, fd2;
	umask(0);				// reset the create document mask.

	if ((pid=fork()) > 0)	// terminate the parent process
	{
		exit(0);
	}
	else if (pid < 0)
	{
		exit(1);
	}

	// only the child process would comes here
	setsid();				// promote to a new process group, and to be the first process of this group, so it can detach from current terminal

	signal(SIGHUP, SIG_IGN);
	if ((pid=fork()) > 0)	// fork again, and terminate the first child process
	{
		exit(0);
	}
	else if (pid< 0)
	{
		exit(1);
	}

	// only the second child process would comes here
	// change the working directory
	if (pszWorkDir == 0)
	{
		char currDir[1024] = "";
		GetCurrentDir(currDir, 1024);
		chdir(currDir);
	}
	else
	{
		chdir(pszWorkDir);
	}

	// the second child process is not the first process of the new group, close all the files
	for (int i=0; i<NOFILE; i++)
	{
		close(i); 
	}

	// redirect standard input, output, error to /dev/null
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);
#endif
}


} // namespace vs

#endif //__VS_FUNCTIONS_H__
